#pragma once
#include <functional>
#include <string>
#include "log.hpp"
#include "Socket.hpp"
#include <unistd.h>
#include <signal.h>

using func_t = std::function<std::string(std::string& package)>;
extern Log lg;

class TcpServer
{
public:
    TcpServer(uint16_t port, func_t callback)
        :port_(port)
        ,callback_(callback)
    {}
    bool InitServer()
    {
        listensock_.Socket();
        listensock_.Bind(port_);
        listensock_.Listen();
        lg(Info, "init server ... done");
        return true;
    }
    void Start()
    {
        //防止僵尸进程，如果收到SIGCHLD信号（即有子进程结束），则忽略它，不执行默认的操作。
        //这里的默认操作往往是生成一个僵尸进程。在Unix-like系统中，当一个子进程结束时，它不会立即消失，而是留在系统中，等待父进程读取其退出状态。
        //在这个过程中，子进程被称为僵尸进程。如果父进程没有正确地处理这个状态，那么这将导致资源泄露，因为每个僵尸进程都会占用一些系统资源。
        //通过设置SIGCHLD为SIG_IGN，父进程可以告诉操作系统，我不关心我的子进程何时结束，你可以立即清除他们。
        signal(SIGCHLD, SIG_IGN);
        //如果收到了SIGPIPE信号（即尝试写入已经被关闭的socket或者管道），那么就忽略它，不采取默认的行动。
        //默认的行动是终止进程，所以如果不希望程序在这种情况时终止，就需要忽略这个信号。
        signal(SIGPIPE, SIG_IGN);
        while(true)
        {
            std::string clientip;
            uint16_t clientport;
            int sockfd = listensock_.Accept(&clientip, &clientport);
            if(sockfd < 0) continue;
            lg(Info, "accept a new link, sockfd: %d, clientip: %s, clientport: %d", sockfd, clientip.c_str(), clientport);
            //提供服务
            if(fork() == 0)
            {
                //child进程
                //子进程中相当于拷贝了一份资源，子进程要这个已经没有用了。不如直接关闭掉。它只关心accept中的sockfd
                //因为这个sockfd中已经bind了服务端和客户端的信息了。
                listensock_.Close();
                std::string inbuffer_stream;
                //数据计算
                while(true)
                {
                    char buffer[128];
                    ssize_t n = read(sockfd, buffer, sizeof(buffer));
                    if(n > 0)
                    {
                        buffer[n] = 0;
                        inbuffer_stream += buffer;

                        lg(Debug, "debug: %s\n", inbuffer_stream.c_str());

                        while(true)
                        {
                            std::string info = callback_(inbuffer_stream);
                            if(info.empty()) break;
                            lg(Debug, "info: %s\n", info.c_str());

                            //write
                            write(sockfd, info.c_str(), info.size());
                        }

                        std::cout << "write success " << std::endl;
                    }
                    else if(n == 0) break;
                    else break;
                }


                exit(0);
            }
            //father
            close(sockfd);
        }
    }
    ~TcpServer()
    {

    }
private:
    uint16_t port_;
    Sock listensock_;
    func_t callback_;
};